package com.one.oa.api.service.impl;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.one.oa.api.bo.UserBo;
import com.one.oa.api.bo.UserFindBo;
import com.one.oa.api.bo.UserNameBo;
import com.one.oa.api.bo.UserPhoneBo;
import com.one.oa.api.service.UserService;

import com.one.oa.api.util.JwtUtil;
import com.one.oa.api.util.PhoneUtil;
import com.one.oa.constants.RedisKey;
import com.one.oa.dao.UserDao;
import com.one.oa.dao.UserDetailDao;
import com.one.oa.dao.UserMsgDao;
import com.one.oa.entity.User;
import com.one.oa.entity.UserDetail;
import com.one.oa.entity.UserMsg;
import com.one.oa.type.UserMsgType;
import com.one.oa.vo.R;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
* @author Lnemo
* @description 针对表【t_user(1.会员表)】的数据库操作Service实现
* @createDate 2023-03-25 08:49:30
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserDao, User>
    implements UserService {
    @Resource
    private UserDao dao;
    @Resource
    private UserDetailDao detailDao;
    @Resource
    private UserMsgDao msgDao;

    @Value("${oa.key.pri}")
    private String prikey;
    @Value("${oa.key.pub}")
    private String pubkey;
    @Resource
    private StringRedisTemplate template;

    @Override
    public R checkName(String name) {
        //1.校验
        if(StringUtils.hasLength(name)){
            //2.查询数据库
            User user=dao.selectOne(new QueryWrapper<User>().eq("username",name.trim()));
            //3.校验
            if(user==null){
                //可用
                return R.ok();
            }else {
                return R.fail("亲，用户名已存在！");
            }
        }
        return R.fail("亲，用户名空了呀！");
    }

    @Override
    public R all() {
        return R.ok(dao.selectList(null));
    }

    @Override
    public R loginName(UserNameBo bo) {
        //1.校验
        if(bo!=null){
            //2.查询数据库 昵称或手机号
            User user=dao.selectOne(new QueryWrapper<User>().eq("phone",bo.getName()).or().eq("username",bo.getName()));
            //3.校验用户是否存在
            if(user!=null){
                //4.是否在线
                if(!template.hasKey(RedisKey.AUTH_USER+user.getId())){
                    //5.校验密码
                    if(user.getPassword().equals(SecureUtil.rsa(prikey,pubkey).encryptBase64(bo.getPassword(), KeyType.PrivateKey))){
                        //6.密码校验成功 本次登录成功,生成令牌 JWT算法
                        user.setPassword("");
                        String token= JwtUtil.createJwt(JSON.toJSONString(user));
                        //7.存储令牌 设置有效期 30分钟 Redis
                        //记录 在线的令牌 -前后端登录
                        template.opsForValue().set(RedisKey.AUTH_TOKEN+token,user.getId().toString(),30, TimeUnit.MINUTES);
                        //记录 在线的用户 -唯一登录
                        template.opsForValue().set(RedisKey.AUTH_USER+user.getId(),token,30,TimeUnit.MINUTES);
                        msgDao.insert(new UserMsg(user.getId(), UserMsgType.登录消息.getValue(),"欢迎你，登录本系统","你通过账号密码完成了登录"));
                        //8.返回信息 令牌携带
                        return R.ok(token);
                    }
                }else {
                    return R.fail("亲，你的账号已在其他设备登录，本次不允许登录！");
                }
            }
        }
        return R.fail("亲，账号或密码不正确！");
    }

    @Override
    public R loginCode(UserPhoneBo bo) {
        //1,校验
        if(bo!=null){
            //2.验证是否存在登录的短信验证码
            if(template.hasKey(RedisKey.AUTH_LOGINCODE+bo.getPhone())){
                //3.查询数据库
                User user=dao.selectOne(new QueryWrapper<User>().eq("phone",bo.getPhone()));
                //4.校验 账号是否存在
                if(user!=null){
                    //5.是否在线
                    if(!template.hasKey(RedisKey.AUTH_USER+user.getId())){
                        //6.校验 短信验证码
                        if(bo.getCode()==Integer.parseInt(template.opsForValue().get(RedisKey.AUTH_LOGINCODE+bo.getPhone()))){
                            //7.密码校验成功 本次登录成功,生成令牌 JWT算法
                            user.setPassword("");
                            String token= JwtUtil.createJwt(JSON.toJSONString(user));
                            //8.存储令牌 设置有效期 30分钟 Redis
                            //记录 在线的令牌 -前后端登录
                            template.opsForValue().set(RedisKey.AUTH_TOKEN+token,user.getId().toString(),30, TimeUnit.MINUTES);
                            //记录 在线的用户 -唯一登录
                            template.opsForValue().set(RedisKey.AUTH_USER+user.getId(),token,30,TimeUnit.MINUTES);
                            //9.删除登录验证码
                            template.delete(RedisKey.AUTH_LOGINCODE+bo.getPhone());
                            msgDao.insert(new UserMsg(user.getId(), UserMsgType.登录消息.getValue(),"欢迎你，登录本系统","你通过手机号验证码完成了登录"));
                            //10.返回信息 令牌携带
                            return R.ok(token);
                        }
                    }else {
                        return R.fail("亲，你的账号已在其他设备登录，本次不允许登录！");
                    }
                }
            }
        }
        return R.fail("亲，验证码不存在或到期！");
    }

    @Override
    public R loginOut(String token) {
        //1.校验
        if(StringUtils.hasLength(token)){
            //2.校验令牌是否有效
            if(template.hasKey(RedisKey.AUTH_TOKEN+token)){
                //3.令牌有效  允许退出
                String uid=template.opsForValue().get(RedisKey.AUTH_TOKEN+token);
                template.delete(RedisKey.AUTH_USER+uid);
                template.delete(RedisKey.AUTH_TOKEN+token);
                //4.返回
                return R.ok();
            }
        }
        return R.fail("亲，请确认登录状态！");
    }

    @Override
    public R findPass(UserFindBo bo) {
        //1.校验
        if(bo!=null) {
            //2.验证 验证码校验是否成功
            if (template.opsForSet().isMember(RedisKey.AUTH_FINDPHONE, bo.getPhone())) {
                //3.密码 转为密文
                String pass = SecureUtil.rsa(prikey, pubkey).encryptBase64(bo.getPassword(), KeyType.PrivateKey);
                //4.修改密码
                if (dao.updatePass(bo.getPhone(), pass) > 0) {
                    //5.删除 记录的手机号
                    template.opsForSet().remove(RedisKey.AUTH_FINDPHONE,bo.getPhone());

                    return R.ok();
                }
            }
        }
        return R.fail("亲，密码找回失败，请联系客服！");
    }

    @Override
    public R updatePass(String token, String password) {
        //1.校验
        if(StringUtils.hasLength(password)){
            //2.密码 转为 密文
            String pass = SecureUtil.rsa(prikey, pubkey).encryptBase64(password, KeyType.PrivateKey);
            //3.获取令牌对应的uid
            int uid=Integer.parseInt(template.opsForValue().get(RedisKey.AUTH_TOKEN+token));
            //4.修改密码
            if(dao.updateById(new User(uid,pass))>0){
                //5.修改成功 清除在线的令牌信息 ，需要重新登录
                template.delete(RedisKey.AUTH_USER+uid);
                template.delete(RedisKey.AUTH_TOKEN+token);

                return R.ok();
            }
        }
        return R.fail("亲，密码修改失败，请自我反思！");
    }

    @Override
    public R checkToken(String token) {
        if(template.hasKey(RedisKey.AUTH_TOKEN+token)){
            return R.ok();
        }
        return R.fail();
    }

    @Override
    public R checkPhone(String phone) {
        //1.校验
        if(PhoneUtil.checkPhone(phone)){
            //2.查询
            User user=dao.selectOne(new QueryWrapper<User>().eq("phone",phone));
            if(user==null){
                //可用
                return R.ok();
            }else {
                return R.fail("亲，手机号已存在！");
            }
        }
        return R.fail("亲，手机号格式不正确！");
    }
    @Override
    public R register(UserBo bo) {
        //1.校验
        if(bo!=null){
            //2.校验是否验证过注册验证码
            if(template.opsForSet().isMember(RedisKey.AUTH_ADDPHONE,bo.getPhone())){
                //3.校验 用户名或手机号 是否存在
                User user=dao.selectOne(new QueryWrapper<User>().eq("phone",bo.getPhone()).or().eq("username",bo.getUsername()));
                if(user==null){
                    //4.实现注册，操作数据库
                    user=new User();
                    BeanUtils.copyProperties(bo,user);
                    user.init();
                    //5.实现密码的密文处理
                    user.setPassword(SecureUtil.rsa(prikey,pubkey).encryptBase64(user.getPassword(), KeyType.PrivateKey));
                    if(dao.insert(user)>0){
                        //6.初始化
                        detailDao.insert(new UserDetail(user.getId()));
                        //7.注册成功，返回结果
                        return R.ok();
                    }
                }else {
                    return R.fail("亲，用户名或手机号已存在！");
                }
            }else {
                return R.fail("亲，该手机号没有校验验证码！");
            }
        }
        return R.fail("亲，注册失败了！");
    }

}




